﻿#region File Header
//============================================================================
//  FileName    :	SerializableDictionary.cs
//
//  Description :	可XML序列化的泛型Dictionary
//
//  Copyright (C) 2008, GrapeCity Inc.  All rights reserved.
//============================================================================
//
//----------------------------------------------------------------------------
//  Update Log:
//
//  Status                Date                      Name               BUG-ID
//----------------------------------------------------------------------------
// Created         7/22/2008 2:11:34 PM     	    CaiShengRong		 	None
//----------------------------------------------------------------------------
#endregion

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.Runtime.Serialization;

namespace SPMS.Utility
{
    /// <summary>
    /// 可XML序列化的泛型Dictionary
    /// </summary>
    /// <typeparam name="TKey">The type of the key.</typeparam>
    /// <typeparam name="TValue">The type of the value.</typeparam>
    /// <remarks></remarks>
    /// <history>
    /// [CaiShengRong]   2008/10/22 10:07    Created
    /// </history>
    [XmlRoot("dictionary"), Serializable]
    public class SerializableDictionary<TKey, TValue>
        : Dictionary<TKey, TValue>, IXmlSerializable
    {
        #region 构造函数

        /// <summary>
        /// Initializes a new instance of the <see cref="SerializableDictionary&lt;TKey, TValue&gt;"/> class.
        /// </summary>
        /// <remarks></remarks>
        /// <history>
        /// [CaiShengRong]   2008/10/23 10:40    Created
        /// </history>
        public SerializableDictionary()
            : base()
        {

        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SerializableDictionary&lt;TKey, TValue&gt;"/> class.
        /// </summary>
        /// <param name="dictionary">The dictionary.</param>
        /// <remarks></remarks>
        /// <history>
        /// [CaiShengRong]   2008/10/23 10:40    Created
        /// </history>
        public SerializableDictionary(IDictionary<TKey, TValue> dictionary)
            : base(dictionary)
        {

        }


        /// <summary>
        /// Initializes a new instance of the <see cref="SerializableDictionary&lt;TKey, TValue&gt;"/> class.
        /// </summary>
        /// <param name="comparer">The comparer.</param>
        /// <remarks></remarks>
        /// <history>
        /// [CaiShengRong]   2008/10/23 10:40    Created
        /// </history>
        public SerializableDictionary(IEqualityComparer<TKey> comparer)
            : base(comparer)
        {
        }


        /// <summary>
        /// Initializes a new instance of the <see cref="SerializableDictionary&lt;TKey, TValue&gt;"/> class.
        /// </summary>
        /// <param name="capacity">The capacity.</param>
        /// <remarks></remarks>
        /// <history>
        /// [CaiShengRong]   2008/10/23 10:40    Created
        /// </history>
        public SerializableDictionary(int capacity)
            : base(capacity)
        {

        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SerializableDictionary&lt;TKey, TValue&gt;"/> class.
        /// </summary>
        /// <param name="capacity">The capacity.</param>
        /// <param name="comparer">The comparer.</param>
        /// <remarks></remarks>
        /// <history>
        /// [CaiShengRong]   2008/10/23 10:40    Created
        /// </history>
        public SerializableDictionary(int capacity, IEqualityComparer<TKey> comparer)
            : base(capacity, comparer)
        {

        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SerializableDictionary&lt;TKey, TValue&gt;"/> class.
        /// </summary>
        /// <param name="info">A <see cref="T:System.Runtime.Serialization.SerializationInfo"/> object containing the information required to serialize the <see cref="T:System.Collections.Generic.Dictionary`2"/>.</param>
        /// <param name="context">A <see cref="T:System.Runtime.Serialization.StreamingContext"/> structure containing the source and destination of the serialized stream associated with the <see cref="T:System.Collections.Generic.Dictionary`2"/>.</param>
        /// <remarks></remarks>
        /// <history>
        /// [CaiShengRong]   2008/10/23 10:40    Created
        /// </history>
        protected SerializableDictionary(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {

        }

        #endregion

        #region Public Property


        /// <summary>
        /// Gets or sets the with the specified key.
        /// </summary>
        /// <value></value>
        /// <remarks></remarks>
        /// <history>
        /// [CaiShengRong]   2008/12/11 17:31    Created
        /// </history>
        public new TValue this[TKey key]
        {
            get
            {
                if(this.Keys.Contains(key))
                {
                    //TValue val;
                    //this.TryGetValue(key, out val);

                    //return val;
                    return base[key];
                }
                else
                {

                    return ObjectUtility.DefaultValue<TValue>();
                }
            }
            set
            {
                if(this.Keys.Contains(key))
                {

                    if(!base[key].Equals(value))
                    {
                        _hasPropertyChanged = true;
                        base[key] = value;
                    };
                    
                }
                else
                {
                    this.Add(key, value);
                    _hasPropertyChanged = true;
                }


            }
        }

        /// <summary>
        /// 
        /// </summary>
        private bool _hasPropertyChanged = false;

        /// <summary>
        /// 判断配置数据是否发生变更
        /// </summary>
        /// <value><c>true</c>如果数据发生变更则返回True<c>false</c>如果数据未发生变更则返回False</value>
        /// <remarks></remarks>
        /// <history>
        /// [CaiShengRong]   2008/10/24 9:47    Created
        /// </history>
        [XmlIgnore()]
        public bool HasPropertyChanged
        {
            get
            {
                return _hasPropertyChanged;
            }

            set
            {
                _hasPropertyChanged = value;
            }
        }

        #endregion 

        #region IXmlSerializable Members
        /// <summary>
        /// このメソッドは予約されているため、使用できません。IXmlSerializable インターフェイスを実装する場合、このメソッドから null (Visual Basic では Nothing) を返す必要があります。また、カスタム スキーマの指定が要求されている場合は、このクラスに <see cref="T:System.Xml.Serialization.XmlSchemaProviderAttribute"/> を適用します。
        /// </summary>
        /// <returns>
        /// 	<see cref="M:System.Xml.Serialization.IXmlSerializable.WriteXml(System.Xml.XmlWriter)"/> メソッドによって生成され <see cref="M:System.Xml.Serialization.IXmlSerializable.ReadXml(System.Xml.XmlReader)"/> メソッドによって処理されるオブジェクトの XML 表現を記述する <see cref="T:System.Xml.Schema.XmlSchema"/>。
        /// </returns>
        /// <remarks></remarks>
        /// <history>
        /// [CaiShengRong]   2008/10/23 10:40    Created
        /// </history>
        public System.Xml.Schema.XmlSchema GetSchema()
        {
            return null;
        }

        /// <summary>
        /// 从对象的 XML 表示形式生成该对象
        /// </summary>
        /// <param name="reader">オブジェクトの逆シリアル化元である <see cref="T:System.Xml.XmlReader"/> ストリーム。</param>
        public void ReadXml(System.Xml.XmlReader reader)
        {

            XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
            XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));
            bool wasEmpty = reader.IsEmptyElement;
            reader.Read();

            if (wasEmpty)
                return;
            while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
            {
                reader.ReadStartElement("item");
                reader.ReadStartElement("key");
                TKey key = (TKey)keySerializer.Deserialize(reader);
                reader.ReadEndElement();
                reader.ReadStartElement("value");
                TValue value = (TValue)valueSerializer.Deserialize(reader);
                reader.ReadEndElement();
                this.Add(key, value);
                reader.ReadEndElement();
                reader.MoveToContent();

            }
            reader.ReadEndElement();

        }


        /// <summary>
        /// 将对象转换为其 XML 表示形式
        /// </summary>
        /// <param name="writer">オブジェクトのシリアル化先の <see cref="T:System.Xml.XmlWriter"/> ストリーム。</param>
        public void WriteXml(System.Xml.XmlWriter writer)
        {

            XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
            XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));
            foreach (TKey key in this.Keys)
            {
                writer.WriteStartElement("item");
                writer.WriteStartElement("key");
                keySerializer.Serialize(writer, key);
                writer.WriteEndElement();
                writer.WriteStartElement("value");
                TValue value = this[key];
                valueSerializer.Serialize(writer, value);
                writer.WriteEndElement();
                writer.WriteEndElement();
            }

        }

        #endregion

    }
}
